<?php

namespace Fox;

class UrlParse {

	public $url;
	private $controller_path;
	private $routes;

	public function __construct($controller_path, $routes = []) {
		$this->controller_path = $controller_path;
		$this->routes = $routes;
	}

	public function resetRoutes($routes) {
		$this->routes = $routes;
	}

	public function start($url = false) {
		$reqUrl = $url ?? $this->getUrlPath();
		$this->url = trim($this->applyUserRoute($reqUrl), '/');
		if (!$this->isClosure) {
			$this->parse();
		}
	}

	/**
	 * 无论有没有开启伪静态，获取纯mvc路径url
	 * domain.com/control/action 或者 domain.com/index.php/control/action
	 * @return string
	 */
	public function getUrlPath() {
		$name = $_SERVER['SCRIPT_NAME'];
		$url = $_SERVER['REQUEST_URI'];
		if (strpos($url, $name) === 0) {
			$url = substr($url, strlen($name));
		}
		if (($pos = stripos($url, '?')) !== false) {
			$url = substr($url, 0, $pos);
		}
		return trim($url, '/');
	}

	private function applyUserRoute($url) {
		$routes = $this->routes;
		if (!empty($routes)) {
			//实际请求的http method
			$req_method = $this->getHttpMethod();
			foreach ($routes as $source => $to) {
				$ret = $this->parseUrlRule($source, $to, $req_method, $url);
				if ($ret !== false) {
					return $ret;
				}
			}
		}
		return $url;
	}

	public $isClosure = false;
	private $Closure;
	private $urlSeg;

	public function callClosure() {
		return call_user_func_array($this->Closure, $this->urlSeg);
	}

	private function parseUrlRule($source, $to, $req_method, $url) {
		$this->isClosure = false;
		$source = str_replace('/', '\\/', $source); //将/（url分隔符）替换为\/避免正则出错
		$parts = explode('@', $source);
		$source = count($parts) == 1 ? $parts[0] : $parts[1]; //去掉method的url模式
		$method = strtolower(count($parts) == 1 ? '' : $parts[0]); //需要匹配的 http method

		if ((empty($method) || $method == $req_method) && preg_match("/^$source$/i", $url, $matchs)) {
			if (is_callable($to)) {
				return $this->setClosure($to, $matchs);
			} else {
				return $this->resetUrl($to, $matchs);
			}
		}
		return false;
	}

	private function setClosure($to, $matchs) {
		$this->isClosure = true;
		array_shift($matchs);
		$this->urlSeg = $matchs;
		$this->Closure = $to;
		return '';
	}

	private function resetUrl($to, $matchs) {
		for ($i = 1; $i < count($matchs); $i++) {
			$to = str_replace('$' . $i, $matchs[$i], $to);
		}
		return $to;
	}

	private $methods = array('post', 'put', 'get', 'delete', 'patch', 'head');

	public function getHttpMethod() {
		static $method;
		if (empty($method)) {
			$method = strtolower(isset($_REQUEST[REST_METHOD_NAME]) ? $_REQUEST[REST_METHOD_NAME] : $_SERVER['REQUEST_METHOD']);
			if(!in_array($method,$this->methods)){
				$method='get';
			}
			//去掉rest请求方法参数
			unset($_GET[REST_METHOD_NAME]);
			unset($_POST[REST_METHOD_NAME]);
			unset($_REQUEST[REST_METHOD_NAME]);
		}
		return $method;
	}

	private $paths;

	private $dir;

	/**
	 * 分析url
	 */
	private function parse() {
		$paths = explode('/', $this->url);
		$dir = '';
		for ($i = 0, $len = count($paths); ($i < $len && !empty($paths[$i]) && is_dir(combine_paths($this->controller_path, $dir, ucfirst($paths[$i])))); $i++) {
			$dir .= '/' . ucfirst($paths[$i]);
		}
		$this->dir = ltrim($dir, '/');
		$this->paths = empty($this->dir) ? $paths : array_slice($paths, $i);
	}

	/**
	 * 获取controller路径，即controllers目录下子目录，如果没子目录则返回空，
	 * @return mixed
	 */
	public function getDir() {
		return $this->dir;
	}

	/**
	 * 获取controller名字 没有返回空
	 * @return string
	 */
	public function getController() {
		return ucfirst(empty($this->paths) ? '' : $this->paths[0]);
	}

	/**
	 * 获取action名字，没有返回空
	 * @return null
	 */
	public function getAction() {
		return count($this->paths) > 1 ? $this->paths[1] : '';
	}

	/**
	 * 获取分析后的url路径数组
	 * @return mixed
	 */
	public function getPaths() {
		return $this->paths;
	}
}